#include "HTTPrequest.h"

const std::unordered_set<std::string> HTTPrequest::DEFAULT_HTML{
    "/index", "/welcome", "/video", "/picture"}; // 由于是const，初始化后值不能被修改，而且静态不属于某个对象

void HTTPrequest::init()
{
    _method = _path = _version = _body = "";
    _state = REQUEST_LINE;
    _header.clear();
    _post.clear();
}
// 解析HTTP请求
bool HTTPrequest::parse(Buffer &buff)
{
    const char CRLF[] = "\r\n"; // 查找用于分割行
    if (buff.readableBytes() <= 0)
    {
        return false;
    }
    while (buff.readableBytes() && _state != FINISH)
    {
        const char *lineEnd = std::search(buff.curReadPtr(), buff.curWritePtrConst(), CRLF, CRLF + 2);
        std::string line(buff.curReadPtr(), lineEnd);
        switch (_state)
        {
        case REQUEST_LINE:
            if (!_parseRequestLine(line))
            {
                return false;
            }
            _parsePath();
            break;
        case HEADERS:
            _parseRequestHeader(line);
            if (buff.readableBytes() <= 2)
            {
                _state = FINISH;
            }
            break;
        case BODY:
            _parseDataBody(line);
            break;
        default:
            break;
        }
        if (lineEnd == buff.curWritePtr())
        {
            break;
        }
        buff.updateReadPtrUntilend(lineEnd + 2);
    }
    return true;
}

bool HTTPrequest::_parseRequestLine(const std::string &line) // 解析请求行
{
    std::regex patten("^([^ ]*) ([^ ]*) HTTP/([^ ]*)$");
    std::smatch subMatch; // 容器的别名，有点像迭代器
    if (regex_match(line, subMatch, patten))
    {
        _method = subMatch[1];
        _path = subMatch[2];
        _version = subMatch[3];
        _state = HEADERS;
        return true;
    }
    return false;
}
void HTTPrequest::_parseRequestHeader(const std::string &line) // 解析请求头
{
    std::regex patten("^([^:]*): ?(.*)$");
    std::smatch subMatch;
    if (regex_match(line, subMatch, patten))
    {
        _header[subMatch[1]] = subMatch[2];
    }
    else
    {
        _state = BODY;
    }
}
void HTTPrequest::_parseDataBody(const std::string &line) // 解析数据体
{
    _body = line;
    _parsePost();
    _state = FINISH;
}
void HTTPrequest::_parsePost()
{
    if (_method == "POST" && _header["Content-Type"] == "application/x-www-form-urlencoded")
    {
        if (_body.size() == 0)
        {
            return;
        }
        std::string key, value;
        int num = 0;
        int n = _body.size();
        int i = 0, j = 0;
        for (; i < n; ++i)
        {
            char ch = _body[i];
            switch (ch)
            {
            case '=':
                key = _body.substr(j, i - j);
                j = i + 1;
                break;
            case '+':
                _body[i] = ' ';
                break;
            case '%':
                num = converHex(_body[i + 1] * 16 + converHex(_body[i + 2]));
                _body[i + 2] = num % 10 + '0';
                _body[i + 1] = num / 10 + '0';
                i += 2;
                break;
            case '&':
                value = _body.substr(j, i - j);
                j = i + 1;
                _post[key] = value;
                break;
            default:
                break;
            }
        }
        assert(j <= i);
        if (_post.count(key) == 0 && j < i)
        {
            value = _body.substr(j, i - j);
            _post[key] = value;
        }
    }
}

int HTTPrequest::converHex(char ch) // 十六进制转10进制
{
    if (ch >= 'A' && ch <= 'F')
        return ch - 'A' + 10;
    if (ch >= 'a' && ch <= 'f')
        return ch - 'a' + 10;
    return ch;
}
void HTTPrequest::_parsePath()
{
    if (_path == "/")
    {
        _path = "/index.html";
    }
    else
    {
        for (auto &item : DEFAULT_HTML)
        {
            if (item == _path)
            {
                _path += ".html";
                break;
            }
        }
    }
}
// 获取HTTP信息
std::string HTTPrequest::path() const
{
    return _path;
}
std::string &HTTPrequest::path()
{
    return _path;
}
std::string HTTPrequest::method() const
{
    return _method;
}
std::string HTTPrequest::version() const
{
    return _version;
}
std::string HTTPrequest::getPost(const std::string &key) const
{
    assert(key != "");
    if (_post.count(key) == 1)
    {
        return _post.find(key)->second;
    }
    return "";
}
std::string HTTPrequest::getPost(const char *key) const
{
    assert(key != nullptr);
    if (_post.count(key) == 1)
    {
        return _post.find(key)->second;
    }
    return "";
}
// 是否保持长连接，避免tcp三次握手
bool HTTPrequest::isKeepAlive() const
{
    if (_header.count("Connection") == 1)
    {
        return _header.find("Connection")->second == "keep-alive" && _version == "1.1";
    }
    return false;
}